home *** CD-ROM | disk | FTP | other *** search
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; ;;;;;
- ;;; Copyright (c) 1989 by William Schelter,University of Texas ;;;;;
- ;;; All rights reserved ;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ;; See the doc/DOC file for information on emit-fn and
- ;; make-all-proclaims. The basic idea is to utilize information gathered
- ;; by the compiler in a compile of a system of files in order to generate
- ;; better code on subsequent compiles of the system. To do this a file
- ;; sys-proclaim.lisp should be produced.
-
- ;; Additionally cross reference information about functions in the system is
- ;; collected.
-
- (in-package 'compiler)
- (import 'sloop::sloop)
-
- (defstruct fn
- name ;; name of THIS FUNCTION
- def ;; defun, defmacro
- value-type ;; If this function's body contained
- ;; (cond ((> a 3) 7)
- ;; ((> a 1) (foo)))
- ;; then the return type of 7 is known at compile time
- ;; and value-type would be fixnum. [see return-type]
- fun-values ;; list of functions whose values are the values of THIS FN
- ;; (foo) in the previous example.
- callees ;; list of all functions called by THIS FUNCTION
- return-type ;; Store a return-type computed from the fun-values
- ;; and value-type field. This computation is done later.
- arg-types ;; non optional arg types.
- no-emit ;; if not nil don't emit declaration.
- macros
- )
-
- (defvar *other-form* (make-fn))
- (defvar *all-fns* nil)
- (defvar *call-table* (make-hash-table))
- (defvar *current-fn* nil)
- (defun add-callee (fname)
- (cond ((consp fname)
- (or (eq (car fname) 'values)
- (add-callee (car fname))))
- ((eq fname 'single-value))
- (fname (pushnew fname (fn-callees (current-fn))))))
-
- (defun add-macro-callee (fname)
- (or
- ;; make sure the macro fname is not shadowed in the current environment.
- (sloop::sloop for v in *funs*
- when (and (consp v) (eq (car v) fname))
- do (return t))
- (pushnew fname (fn-macros (current-fn)))))
-
- (defun clear-call-table ()
- (setf *current-fn* nil)
- (setq *all-fns* nil)
- (setq *other-form* (make-fn :name 'other-form))
- (clrhash *call-table*)
- (setf (gethash 'other-form *call-table*) *other-form*)
- )
-
- (defun emit-fn (flag) (setq *record-call-info* flag))
-
- (defun type-or (a b)
- (if (eq b '*) '*
- (case a
- ((nil) b)
- ((t inline) t)
- ((fixnum inline-fixnum fixnum-value) (if (eq b 'fixnum) 'fixnum
- (type-or t b)))
- (otherwise '*)
- )))
-
- (defun current-fn ()
- (cond ((and (consp *current-form*)
- (member (car *current-form*) '(defun defmacro))
- (symbolp (second *current-form*))
- (symbol-package (second *current-form*));;don't record gensym'd
- )
- (cond ((and *current-fn*
- (equal (second *current-form*) (fn-name *current-fn*)))
- *current-fn*)
- (t
- (unless
- (setq *current-fn*
- (gethash (second *current-form*) *call-table*))
- (setq *current-fn* (make-fn :name (second *current-form*)
- :def (car *current-form*)))
- (setf (gethash (second *current-form*) *call-table*)
- *current-fn*)
- (setq *all-fns* (cons *current-fn* *all-fns*)))
- *current-fn*)))
- ;; catch all for other top level forms
- (t *other-form*)))
-
- (defun who-calls (f)
- (sloop for (ke val) in-table *call-table*
- when (or (member f (fn-callees val))
- (member f (fn-macros val)))
- collect ke))
-
-
- (defun add-value-type (x fn &aux (current-fn (current-fn)))
- (cond (fn (pushnew fn
- (fn-fun-values current-fn) :test 'equal))
- (t
- (setf (fn-value-type current-fn)
- (type-or (fn-value-type current-fn) x)))))
-
-
- (defun get-var-types (lis)
- (sloop::sloop for v in lis collect (var-type v)))
-
- (defun record-arg-info( lambda-list &aux (cf (current-fn)))
- (setf (fn-arg-types cf) (get-var-types (car lambda-list)))
- (when (sloop::sloop for v in (cdr lambda-list)
- for w in '(&optional &rest &key
- nil &allow-other-keys
- )
- when (and v w) do (return '*))
- (setf (fn-arg-types cf) (nconc(fn-arg-types cf) (list '*)))
- ))
-
- (defvar *depth* 0)
- (defvar *called-from* nil)
-
- (defun get-value-type (fname)
- (cond ((member fname *called-from* :test 'eq) nil)
- (t
- (let ((tem (cons fname *called-from*)))
- (declare (:dynamic-extent tem))
- (let ((*called-from* tem))
- (get-value-type1 fname))))))
-
- (defun get-value-type1 (fname
- &aux tem (*depth* (the fixnum (+ 1 (the fixnum
- *depth* )))))
- (cond ((> (the fixnum *depth*) 100) '*)
- ((setq tem (gethash fname *call-table*))
- (or
- (fn-return-type tem)
- (sloop::sloop with typ = (fn-value-type tem)
- for v in (fn-fun-values tem)
- when (symbolp v)
- do (setq typ (type-or typ (get-value-type v)))
- else
- when (and (consp v) (eq (car v) 'values))
- do
- (setq typ (type-or typ (if (eql (cdr v) 1) t '*)))
- else do (error "unknown fun value ~a" v)
- finally
- ;; if there is no visible return, then we can assume
- ;; one value.
- (or typ (fn-value-type tem)
- (fn-fun-values tem)
- (setf typ t))
- (setf (fn-return-type tem) typ)
- (return typ)
- )))
- ((get fname 'return-type))
- ((get fname 'proclaimed-return-type))
- (t '*)))
-
- (defun result-type-from-loc (x)
- (cond ((consp x)
- (case (car x)
- ((fixnum-value inline-fixnum) 'fixnum)
- (var (var-type (second x)))
- ;; eventually separate out other inlines
- (t (cond ((and (symbolp (car x))
- (get (car x) 'wt-loc))
- t)
- (t (print (list 'type '* x)) '*)))))
- ((or (eq x t) (null x)) t)
- (t (print (list 'type '*2 x)) '*)))
-
-
- (defun small-all-t-p (args ret)
- (and (eq ret t)
- (< (length args) 10)
- (sloop::sloop for v in args always (eq v t))))
-
- ;; Don't change return type but pretend all these are optional args.
-
- (defun no-make-proclaims-hack ()
- (sloop::sloop for (ke val) in-table *call-table*
- do (progn ke) (setf (fn-no-emit val) 1)))
-
-
- (defun make-proclaims ( &optional (st *standard-output*)
- &aux (ht (make-hash-table :test 'equal))
- *print-length* *print-level*
- )
- ; (require "VLFUN"
- ; (concatenate 'string si::*system-directory*
- ; "../cmpnew/lfun_list.lsp"))
-
- (print `(in-package ,(package-name *package*)) st)
- (sloop::sloop with ret with at
- for (ke val) in-table *call-table*
- do
- (cond ((or (eql 1 (fn-no-emit val))
- (not (eq (fn-def val) 'defun))))
- (t (setq ret (get-value-type ke))
- (setq at (fn-arg-types val))
- (push ke (gethash (list at ret) ht)))))
- (sloop::sloop for (at fns) in-table ht
- do
- (print
- `(proclaim '(ftype (function ,@ at) ,@ fns))
- st)))
-
- (defun setup-sys-proclaims()
- (or (gethash 'si::call-test *call-table*)
- (get 'si::call-test 'proclaimed-function)
- (load (concatenate 'string si::*system-directory*
- "../lsp/sys-proclaim.lisp"))
- (no-make-proclaims-hack)
- ))
-
- (defun make-all-proclaims (&rest files)
- (setup-sys-proclaims)
- (dolist (v files)
- (mapcar 'load (directory v)))
- (write-sys-proclaims))
-
- (defun write-sys-proclaims ()
- (with-open-file (st "sys-proclaim.lisp" :direction :output)
- (make-proclaims st)))
-
- (defvar *file-table* (make-hash-table :test 'eq))
-
- (defun add-fn-data (lis &aux tem file)
- (let ((file (and (setq file (si::fp-input-stream *standard-input*))
- (truename file))))
- (dolist (v lis)
- (cond ((eql (fn-name v) 'other-form)
- (setf (fn-name v) (intern
- (concatenate 'string "OTHER-FORM-"
- (namestring file))))
- (setf (get (fn-name v) 'other-form) t)))
- (setf (gethash (fn-name v) *call-table*) v)
- (if (setq tem (gethash (fn-name v) *file-table*))
- (or (equal tem file)
- (format t "~% Warn ~a redefined in ~a. Originally in ~a."
- (fn-name v) file tem)))
- (setf (gethash (fn-name v) *file-table*)
- file))))
-
- (defun dump-fn-data (&optional (file "fn-data.lsp")
- &aux (*package* (find-package "COMPILER"))
- (*print-length* nil)
- (*print-level* nil)
- )
- (with-open-file (st file :direction :output)
- (format st "(in-package 'compiler)(init-fn)~%(~s '(" 'add-fn-data)
- (sloop::sloop for (ke val) in-table *call-table*
- do (progn ke) (print val st))
- (princ "))" st)
- (truename st)))
-
- (defun record-call-info (loc fname)
- (cond ((and fname (symbolp fname))
- (add-callee fname)))
- (cond ((eq loc 'record-call-info) (return-from record-call-info nil)))
- (case *value-to-go*
- (return
- (if (eq loc 'fun-val)
- (add-value-type nil (or fname 'unknown-values))
- (add-value-type (result-type-from-loc loc) nil)))
- (return-fixnum
- (add-value-type 'fixnum nil))
- (return-object
- (add-value-type t nil))
-
- (top (setq *top-data* (cons fname nil))
- ))
- )
-
- (defun list-undefined-functions (&aux undefs)
- (sloop::sloop for (name fn) in-table *call-table*
- declare (ignore name)
- do (sloop for w in (fn-callees fn)
- when (not (or (fboundp w)
- (gethash w *call-table*)
- (get w 'inline-always)
- (get w 'inline-unsafe)
- (get w 'other-form)
- ))
- do (pushnew w undefs)))
- undefs)
-
-
-
- (dolist (v '(throw coerce single-value sort delete remove char-upcase
- si::fset typep))
- (si::putprop v t 'return-type))
-
- (defun init-fn () nil)
-
- (defun list-uncalled-functions ( )
- (let* ((size (sloop::sloop for (ke v)
- in-table *call-table* count t
- do (progn ke v nil)))
- (called (make-hash-table :test 'eq :size (+ 3 size))))
- (sloop::sloop for (ke fn) in-table *call-table*
- declare (ignore ke)
- do (sloop::sloop for w in (fn-callees fn)
- do
- (setf (gethash w called) t))
- (sloop::sloop for w in (fn-macros fn)
- do
- (setf (gethash w called) t))
-
- )
- (sloop::sloop for (ke fn) in-table *call-table*
- when(and
- (not (gethash ke called))
- (member (fn-def fn) '(defun defmacro)
- :test 'eq))
- collect ke)))
-
- ;; redefine the stub in defstruct.lsp
- (defun si::record-fn (name def arg-types return-type)
- (if (null return-type) (setq return-type t))
- (and *record-call-info*
- *compiler-in-use*
- (let ((fn (make-fn :name name
- :def def
- :return-type return-type
- :arg-types arg-types)))
- (push fn *all-fns*)
- (setf (gethash name *call-table*) fn))))
-
- (defun get-packages (&optional (st "sys-package.lisp") pass
- &aux (si::*print-package* t))
- (flet ((pr (x) (format st "~%~s" x)))
- (cond ((null pass)
- (with-open-file (st st :direction :output)
- (get-packages st 'establish)
- (get-packages st 'export)
- (get-packages st 'shadow)
- (format st "~2%")
- (return-from get-packages nil))))
- (dolist (p (list-all-packages))
- (unless
- (member (package-name p)
- '("SLOOP"
- "COMPILER" "SYSTEM" "KEYWORD" "LISP" "USER")
- :test 'equal
- )
- (format st "~2%;;; Definitions for package ~a of type ~a"
- (package-name p) pass)
- (ecase pass
- (establish
- (let ((SYSTEM::*PRINT-PACKAGE* t))
- (pr
- `(in-package ,(package-name p) :use nil
- ,@ (if (package-nicknames p)
- `(:nicknames ',(package-nicknames p)))))))
- (export
- (let ((SYSTEM::*PRINT-PACKAGE* t))
- (pr
- `(in-package ,(package-name p)
- :use
- '(,@
- (mapcar 'package-name (package-use-list p)))
- ,@(if (package-nicknames p)
- `(:nicknames ',(package-nicknames p))))))
- (let (ext (*package* p)
- imps)
- (do-external-symbols (sym p) (push sym ext)
- (or (eq (symbol-package sym) p)
- (push sym imps)))
- (pr `(import ',imps))
- (pr `(export ',ext))))
- (shadow
- (let ((SYSTEM::*PRINT-PACKAGE* t))
- (pr `(in-package ,(package-name p))))
- (let (in out (*package* (find-package "LISP")))
- (dolist (v (package-shadowing-symbols p))
- (cond ((eq (symbol-package v) p)
- (push v in))
- (t (push v out))))
- (pr `(shadow ',in))
- (pr `(shadowing-import ',out))
- (let (imp)
- (do-symbols (v p)
- (cond ((not (eq (symbol-package v) p))
- (push v imp))))
- (pr `(import ',imp))))))))))
-